#include "ApplicationBase.h"
#include <ctime>
#include <cstring>
#include <memory>
#include <fstream>
using namespace std;

ApplicationBase::~ApplicationBase()
{
    if(mInput!=nullptr)
    {
        mInput->release();
        mInput = nullptr;
    }
    if(mWindow!=nullptr)
    {
        glfwDestroyWindow(mWindow);
        mWindow = nullptr;
    }
}
void ApplicationBase::printOpenGLInfo()
{
    POCELAIN_LOG_DEBUG("OpenGL version: %s\n", glGetString(GL_VERSION));
    POCELAIN_LOG_DEBUG("GLSL version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
    POCELAIN_LOG_DEBUG("Vendor: %s\n", glGetString(GL_VENDOR));
    POCELAIN_LOG_DEBUG("Renderer: %s\n", glGetString(GL_RENDERER));
}

ApplicationBase::ApplicationBase(int argc,char **argv)
    :mWindow(nullptr)
    ,mGLMajorVersion(2)
    ,mGLMinorVersion(1)
{
    for(int i = 0 ; i< argc ; ++i)
    {
        this->mArgvs.push_back(argv[i]);
    }
}

void ApplicationBase::versionSelect()
{
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,this->mGLMajorVersion);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,this->mGLMinorVersion);
}
void ApplicationBase::init()
{
    glfwSetErrorCallback([](int error , const char *description)
    {
        POCELAIN_LOG_ERROR("Error code %d description: %s \n", error,description);
    });

    //初始化glfw
    if (!glfwInit())
        exit(EXIT_FAILURE);

    //设置OpenGL的版本
    this->versionSelect();

    //创建窗口
    this->mWindow = glfwCreateWindow(
                                     800,
                                     600,
                                     this->mArgvs[0].c_str(),
                                     NULL,
                                     NULL
                                     );
    if(!this->mWindow)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

    mInput = new InputGLFW(mWindow);

    //绘制对象
    glfwMakeContextCurrent(this->mWindow);

    //注意glewInit调用的时机，一定是创建完窗口后
    GLenum err = glewInit();
    if(err!= GLEW_OK)
    {
        POCELAIN_LOG_ERROR("Error glewInit fail : %s \n", glewGetErrorString(err));
        exit(EXIT_FAILURE);
    }

    mWindowSize = mInput->getWindowSize();
    glViewport(0,0,mWindowSize.x,mWindowSize.y);
    glfwSetCursorPos(mWindow, mWindowSize.x/2, mWindowSize.y/2);

    //垂直同步
    glfwSwapInterval(1);
}
void ApplicationBase::onResize(int width, int height)
{
    mWindowSize.set(width,height);
    glViewport(0,0,mWindowSize.x,mWindowSize.y);
}
int ApplicationBase::run()
{
    this->init();
    printOpenGLInfo();
    clock_t last_time = clock();
    while (!glfwWindowShouldClose(this->mWindow))
    {
        clock_t this_time=clock();
        mInput->update();
        // Window size changed
        auto &&windowSize = mInput->getWindowSize();
        if(mWindowSize != windowSize)
            onResize(windowSize.x,windowSize.y);

        double elapse = (double)(this_time-last_time)/CLOCKS_PER_SEC;
        last_time=this_time;
        this->render(elapse);
    }
    return 0;
}
